package com.zenithmind.common.aspect;

import com.zenithmind.common.annotation.RequireAuth;
import com.zenithmind.common.context.UserContext;
import com.zenithmind.common.exception.ForbiddenException;
import com.zenithmind.common.exception.UnauthorizedException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.List;

/**
 * 权限验证切面
 * 处理@RequireAuth注解的权限验证逻辑
 */
@Slf4j
@Aspect
@Component
@Order(1) // 确保在其他切面之前执行
public class AuthAspect {
    
    @Before("@annotation(requireAuth) || @within(requireAuth)")
    public void checkAuth(JoinPoint joinPoint, RequireAuth requireAuth) {
        // 如果方法上没有注解，检查类上的注解
        if (requireAuth == null) {
            requireAuth = joinPoint.getTarget().getClass().getAnnotation(RequireAuth.class);
        }
        
        if (requireAuth == null) {
            return; // 没有权限要求
        }
        
        // 检查用户是否已登录
        if (!UserContext.isAuthenticated()) {
            log.warn("用户未登录，拒绝访问: {}", joinPoint.getSignature().toShortString());
            throw new UnauthorizedException("用户未登录");
        }
        
        String currentUserId = UserContext.getUserId();
        if (currentUserId == null) {
            log.warn("无法获取用户ID，拒绝访问: {}", joinPoint.getSignature().toShortString());
            throw new UnauthorizedException("无法获取用户信息");
        }
        
        // 检查管理员权限
        if (requireAuth.admin() && !UserContext.isAdmin()) {
            log.warn("用户 {} 尝试访问管理员接口: {}, 用户角色: {}", currentUserId, joinPoint.getSignature().toShortString(), UserContext.getUserRoles());
            throw new ForbiddenException("需要管理员权限");
        }
        
        // 检查角色权限
        String[] requiredRoles = requireAuth.roles();
        if (requiredRoles.length > 0) {
            List<String> userRoles = UserContext.getUserRoles();
            boolean hasRequiredRole = Arrays.stream(requiredRoles)
                    .anyMatch(userRoles::contains);
            
            if (!hasRequiredRole) {
                log.warn("用户 {} 角色不足，需要角色: {}, 当前角色: {}", 
                        currentUserId, Arrays.toString(requiredRoles), userRoles);
                throw new ForbiddenException("角色权限不足");
            }
        }
        
        // 检查资源所有权
        if (requireAuth.allowSelf()) {
            checkResourceOwnership(joinPoint, requireAuth, currentUserId);
        }
        
        log.debug("用户 {} 权限验证通过: {}", currentUserId, joinPoint.getSignature().toShortString());
    }
    
    /**
     * 检查资源所有权
     */
    private void checkResourceOwnership(JoinPoint joinPoint, RequireAuth requireAuth, String currentUserId) {
        // 如果是管理员，跳过所有权检查
        if (UserContext.isAdmin()) {
            return;
        }
        
        String userIdParam = requireAuth.userIdParam();
        Object[] args = joinPoint.getArgs();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Parameter[] parameters = method.getParameters();
        
        // 从方法参数中查找用户ID
        String resourceUserId = null;
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            if (userIdParam.equals(parameter.getName()) && args[i] instanceof String) {
                resourceUserId = (String) args[i];
                break;
            }
        }
        
        // 如果没有在参数中找到，尝试从请求参数中获取
        if (resourceUserId == null) {
            resourceUserId = getRequestParameter(userIdParam);
        }
        
        // 如果仍然没有找到，尝试从路径变量中获取
        if (resourceUserId == null) {
            resourceUserId = getPathVariable(userIdParam);
        }
        
        // 检查资源所有权
        if (resourceUserId != null && !currentUserId.equals(resourceUserId)) {
            log.warn("用户 {} 尝试访问其他用户 {} 的资源: {}", 
                    currentUserId, resourceUserId, joinPoint.getSignature().toShortString());
            throw new ForbiddenException("无权访问其他用户的资源");
        }
    }
    
    /**
     * 从请求参数中获取值
     */
    private String getRequestParameter(String paramName) {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                return request.getParameter(paramName);
            }
        } catch (Exception e) {
            log.debug("获取请求参数失败: {}", paramName, e);
        }
        return null;
    }
    
    /**
     * 从路径变量中获取值（简单实现）
     */
    private String getPathVariable(String varName) {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                String uri = request.getRequestURI();
                // 这里可以实现更复杂的路径变量解析逻辑
                // 暂时返回null，让具体的业务逻辑处理
            }
        } catch (Exception e) {
            log.debug("获取路径变量失败: {}", varName, e);
        }
        return null;
    }
}
